<?php
namespace Game\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\HttpFoundation\Request;
use Game\Entity\Character;
use Game\Factory\ActionFactory;

/**
 * @Entity
 * @Table(name="game_environment", indexes={@index(name="env_type_idx", columns={"env_type"})})
 * @InheritanceType("SINGLE_TABLE")
 * @DiscriminatorColumn(name="env_type", type="string")
 * @DiscriminatorMap({ "battle" = "BattleEnvironment", "walk" = "WalkEnvironment" })
 */
abstract class Environment
{
    /**
     * @Id
     * @Column(type="integer")
     * @GeneratedValue(strategy="AUTO")
     * @var integer
     **/
    protected $id;

    /**
     * @Column(type="datetime")
     * @var \DateTime
     */
    protected $created_at;

    /**
     * @Column(type="datetime")
     * @var \DateTime
     */
    protected $updated_at;

    /**
     * @OneToMany(targetEntity="Character", mappedBy="environment")
     */
    protected $characters;

    /**
     * Actions collection
     * @var array
     */
    protected $_actions = array();

    /**
     * Returns actions collection
     * @return ArrayCollection
     */
    public function getActions()
    {
        return $this->_actions;
    }

    /**
     * Initialize environment. Can't add to constructor, because Doctrine
     * never call constructor
     *
     * @return \Game\Entity\Environment
     */
    public function init()
    {
        $this->_actions = $this->_getActions();
        return $this;
    }

    /**
     * Must return array of actions names
     * @return array
     */
    abstract protected function _getActions();

    public function __construct()
    {
        $this->characters = new ArrayCollection();
    }

    /**
     * Get id
     *
     * @return integer
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set created_at
     *
     * @param datetime $createdAt
     * @return Environment
     */
    public function setCreatedAt($createdAt)
    {
        $this->created_at = $createdAt;
        return $this;
    }

    /**
     * Get created_at
     *
     * @return datetime
     */
    public function getCreatedAt()
    {
        return $this->created_at;
    }

    /**
     * Set updated_at
     *
     * @param datetime $updatedAt
     * @return Environment
     */
    public function setUpdatedAt($updatedAt)
    {
        $this->updated_at = $updatedAt;
        return $this;
    }

    /**
     * Get updated_at
     *
     * @return datetime
     */
    public function getUpdatedAt()
    {
        return $this->updated_at;
    }

    /**
     * Add characters
     *
     * @param Game\Entity\Character $characters
     * @return Environment
     */
    public function addCharacter(\Game\Entity\Character $characters)
    {
        $this->characters[] = $characters;
        return $this;
    }

    /**
     * Get characters
     *
     * @return Doctrine\Common\Collections\Collection
     */
    public function getCharacters()
    {
        return $this->characters;
    }

    /**
     *
     * @param Character $character
     * @return Doctrine\Common\Collections\ArrayCollection
     */
    public function getOtherCharacters($character)
    {
        return $this->getCharacters()->filter(function($elm) use ($character) {
            if( $elm !== $character ) return $elm;
        });
    }

    public function executeCommand(Character $character, Request $request)
    {
        $command = $request->get('command');
        if( !$command )
            throw new \Game\Exception\Environment\CommandNotDefineException('There is no "command" parameter in request');

        if( !$this->validateCommand($command) )
            throw new \Game\Exception\Environment\EnvironmentException('Command has invalid value');

        $this->bindActionsToCharacter($character);
    }

    public function validateCommand($command)
    {
        return in_array($command, $this->getActions(), true);
    }

    public function bindActionsToCharacter(Character $character)
    {
        foreach( $this->getActions() as $action )
        {
            $character->addAction(ActionFactory::getInstance()->createAction($action));
        }
    }
}